﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../objects/head.h"
#include "../global/head.h"
#include <float.h>
#include "misc.h"

namespace xos_common
{
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static misc::POOL * pool_ptr = 0;

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    misc::misc()
    {}

    misc::~misc()
    {}

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int misc::get_addr( POOL *** pppPool, LIST *** pppList )
    {
        int ret = 0;
        if( pppPool )
        {
            *pppPool = &pool_ptr;
        }
        if( pppList )
        {
            *pppList = 0;
        }
        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //  

    int misc::init()
    {
        int nRet = 0;
        return nRet;
    }

    int misc::term()
    {
        int nRet = 0;
        return nRet;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    // i_misc method

    // 以指定进制显示数据内容 : 16, 10, 8
    int misc::bin_to_text( char * lpszOutData, int nOutLen, int * pnOutLen, const unsigned char * lpszInData, int nInLen, int decimal )
    {
        int ret = 0;

        int nLen = 0, nPos = 0;
        char fmt[64] = { 0 };

        switch( decimal )
        {
        case 16:
            {
                g_pSysData->m_pContainer->crt()->strcpy( fmt, sizeof( fmt ), "%02x" );
            }
            break;
        case 10:
            {
                g_pSysData->m_pContainer->crt()->strcpy( fmt, sizeof( fmt ), "%02d" );
            }
            break;
        case 8:
            {
                g_pSysData->m_pContainer->crt()->strcpy( fmt, sizeof( fmt ), "%02o" );
            }
            break;
        default:
            {
                ret = 1;
            }
            break;
        }

        while( ( 0 == ret ) && ( nOutLen > nLen ) && ( nInLen > nPos ) )
        {
            int len = g_pSysData->m_pContainer->crt()->sprintf( lpszOutData + nLen, nOutLen - nLen, fmt, ( int )lpszInData[nPos] );
            nLen += len;
            nPos += 1;
        }

        if( ( 0 == ret ) && pnOutLen )
        {
            *pnOutLen = nLen;
        }

        return ret;
    }

    // 
    // 3des
    // 
    int misc::DoDES( char * Out, const char * In, long datalen, const char * Key, int keylen, bool bEncode )
    {
        int nRet = 0;
        des tool;
        nRet = tool.DoDES( Out, In, datalen, Key, keylen, bEncode );
        return nRet;
    }

    // 
    // crc16
    // 
    unsigned short misc::cal_crc16( const unsigned char * lpData, int nLen )
    {
        return xos_common::cal_crc16( lpData, nLen );
    }

    // 
    // url encode / decode
    // 
    int misc::url_encode( const char * lpszSrc, int nSrcLen, char * lpszDst, int nCharNum )
    {
        int nRet = 0;
        nRet = xos_common::url_encode( lpszSrc, nSrcLen, lpszDst, nCharNum );
        return nRet;
    }

    int misc::url_decode( const char * lpszSrc, int nSrcLen, char * lpszDst, int nCharNum )
    {
        int nRet = 0;
        nRet = xos_common::url_decode( lpszSrc, nSrcLen, lpszDst, nCharNum );
        return nRet;
    }

    // 
    // base64 encode / decode
    // 
    int misc::base64_encode( const char * lpszSrc, int nSrcLen, char * lpszDst, int nCharNum )
    {
        int nRet = 0;

        int nLen = nSrcLen;
        const char * lpszEncode = 0;
        base64 tool;

        tool.Encode( lpszSrc, nLen );
        lpszEncode = tool.EncodedMessage();

        g_pSysData->m_pContainer->crt()->strcpy( lpszDst, nCharNum, lpszEncode );

        return nRet;
    }

    int misc::base64_decode( const char * lpszSrc, int nSrcLen, char * lpszDst, int nCharNum )
    {
        int nRet = 0;

        int nLen = nSrcLen;
        const char * lpszDecode = 0;
        base64 tool;

        tool.Decode( lpszSrc, nLen );
        lpszDecode = tool.DecodedMessage();

        g_pSysData->m_pContainer->crt()->strcpy( lpszDst, nCharNum, lpszDecode );

        return nRet;
    }

    // 
    // 计算分页的url
    // 
    int misc::page_info( int nMaxPage, int nPageNum, int nCurPage, bool bEnable, char * lpszPageInfoUrl, int nBufSize, int * lpnInfoSize )
    {
        int ret = 0;

        int max_num = nMaxPage;
        int begin = 0, end = 0;

        {
            int half = max_num / 2;
            int b = nCurPage - half;
            int e = 0;
            if( b < 0 )
            {
                b = 0;
            }
            e = b + max_num;
            if( e > nPageNum )
            {
                e = nPageNum;
            }
            begin = b;
            end = e;
        }

        std::string fmt_cur_link = "<a href=%d style='text-decoration:underline;'>&lt;%d&gt;</a>";
        std::string fmt_link = "<a href=%d>&lt;%d&gt;</a>";
        std::string style_link = "<style>a:link,a:visited{text-decoration:none;}</style>";

        std::string fmt_cur_none = "<span style='text-decoration:underline;'>&lt;%d&gt;</span>";
        std::string fmt_none = "<span>&lt;%d&gt;</span>";
        std::string style_none = "<style>{text-decoration:none;}</style>";

        std::string * pStyle = &style_link;
        std::string * pFmtCur = &fmt_cur_link;
        std::string * pFmt = &fmt_link;

        if( !bEnable )
        {
            pFmtCur = &fmt_cur_none;
            pStyle = &style_none;
            pFmt = &fmt_none;
        }

        std::string content = *pStyle;

        for( int i = begin; i < end; ++i )
        {
            const std::string * pFormat = pFmt;
            char buf[4096] = { 0 };
            if( i == nCurPage )
            {
                pFormat = pFmtCur;
            }
            if( bEnable )
            {
                g_pSysData->m_pContainer->crt()->sprintf( buf, sizeof( buf ), pFormat->c_str(), i, i + 1 );
            }
            else
            {
                g_pSysData->m_pContainer->crt()->sprintf( buf, sizeof( buf ), pFormat->c_str(), i + 1 );
            }
            content += buf;
        }

        if( lpszPageInfoUrl && ( nBufSize > ( int )content.length() ) )
        {
            g_pSysData->m_pContainer->crt()->strcpy( lpszPageInfoUrl, nBufSize, content.c_str() );
        }

        if( lpnInfoSize )
        {
            *lpnInfoSize = ( int )content.length();
        }

        return ret;
    }

    // 
    // 字串操作
    // 
    const char * misc::split_full_file( const char * lpszFullFile, char * lpszPath, int nSize, int * lpnSize )
    {
        const char * pRet = 0;
        int nFullLen = 0;
        int nPathLen = 0;
        int ret = 0;

        if( 0 == ret )
        {
            const char * lpszW = g_pSysData->m_pContainer->crt()->strrchr( lpszFullFile, '\\' );
            const char * lpszL = g_pSysData->m_pContainer->crt()->strrchr( lpszFullFile, '/' );
            nFullLen = g_pSysData->m_pContainer->crt()->strlen( lpszFullFile );
            pRet = lpszW > lpszL ? lpszW : lpszL;
            if( pRet )
            {
                pRet++;
                nPathLen = ( int )( pRet - lpszFullFile );
            }
            else
            {
                ret = 1;
            }
        }

        if( ( 0 == ret ) && lpszPath && ( nSize > nPathLen ) )
        {
            g_pSysData->m_pContainer->crt()->strncpy( lpszPath, nSize, lpszFullFile, nPathLen );
        }

        if( ( 0 == ret ) && lpnSize )
        {
            *lpnSize = nPathLen;
        }

        return pRet;
    }

    const char * misc::ext( const char * lpszFile, char * lpszName, int nLen, int * lpnLen )
    {
        const char * pRet = 0;
        int nNameLen = 0;
        int ret = 0;

        if( 0 == ret )
        {
            pRet = g_pSysData->m_pContainer->crt()->strrchr( lpszFile, '.' );
            if( pRet )
            {
                pRet++;
                nNameLen = ( int )( pRet - lpszFile - 1 );
            }
            else
            {
                ret = 1;
            }
        }

        if( ( 0 == ret ) && lpszName && ( nLen > nNameLen ) )
        {
            g_pSysData->m_pContainer->crt()->strncpy( lpszName, nLen, lpszFile, nNameLen );
        }

        if( ( 0 == ret ) && lpnLen )
        {
            *lpnLen = nNameLen + 1;
        }

        return pRet;
    }

    int misc::parse_uri_to_property( const char * lpszUri, xos_box::i_property * pProp )
    {
        int ret = 0;

        xos::i_crt * pCrt = g_pSysData->m_pContainer->crt();
        int nLen = pCrt->strlen( lpszUri );
        char buf[4096] = { 0 };
        char * lpszPath = buf;
        int nPathIndex = 0;

        {
            pCrt->strcpy( buf, sizeof( buf ), lpszUri );
        }

        for( int i = 0; i < nLen; ++i )
        {
            if( buf[i] == '/' )
            {
                buf[i] = 0;
            }
            else if( i != nLen - 1 )
            {
                continue;
            }
            if( 0 != *lpszPath )
            {
                pProp->set( nPathIndex, lpszPath );
                nPathIndex++;
            }
            lpszPath = buf + i + 1;
        }

        return ret;
    }

    // \t -> \\t, ' -> \\', " -> \\"
    int misc::trans( const char * lpszSrc, char * lpszDst, int nLen, int * lpnLen )
    {
        const char * pszSrc = lpszSrc;
        int nPos = 0;
        int ret = 0;
        char c = 0;

        while( ( c = *pszSrc++ ) )
        {
            switch( c )
            {
            case '\"':
            case '\'':
            case '\\':
                {
                    if( nPos < nLen - 2 )
                    {
                        lpszDst[nPos + 0] = '\\';
                        lpszDst[nPos + 1] = c;
                    }
                    nPos += 2;
                }
                break;
            case '\t':
                {
                    if( nPos < nLen - 2 )
                    {
                        lpszDst[nPos + 0] = '\\';
                        lpszDst[nPos + 1] = 't';
                    }
                    nPos += 2;
                }
                break;
            case '\r':
                {
                    if( nPos < nLen - 2 )
                    {
                        lpszDst[nPos + 0] = '\\';
                        lpszDst[nPos + 1] = 'r';
                    }
                    nPos += 2;
                }
                break;
            case '\n':
                {
                    if( nPos < nLen - 5 )
                    {
                        lpszDst[nPos + 0] = '\\';
                        lpszDst[nPos + 1] = 'n';
                        lpszDst[nPos + 2] = '\\';
                        lpszDst[nPos + 3] = '\r';
                        lpszDst[nPos + 4] = '\n';
                    }
                    nPos += 5;
                }
                break;
            default:
                {
                    if( nPos < nLen - 1 )
                    {
                        lpszDst[nPos] = c;
                    }
                    nPos += 1;
                }
                break;
            }
        }

        if( nPos < nLen - 1 )
        {
            lpszDst[nPos] = 0;
        }
        else
        {
            ret = 1;
        }

        if( lpnLen )
        {
            *lpnLen = nPos;
        }

        return ret;
    }

    int misc::begin_with( const char * lpszStr, const char * lpszSub )
    {
        int ret = 0;

        int str_len = g_pSysData->m_pContainer->crt()->strlen( lpszStr );
        int sub_len = g_pSysData->m_pContainer->crt()->strlen( lpszSub );

        if( ( 0 == ret ) && ( str_len < sub_len ) )
        {
            ret = 1;
        }

        for( int i = 0; ( 0 == ret ) && ( i < sub_len ); ++i )
        {
            if( lpszStr[i] != lpszSub[i] )
            {
                ret = 1;
                break;
            }
        }

        return ret;
    }

    int misc::end_with( const char * lpszStr, const char * lpszSub )
    {
        int ret = 0;

        int str_len = g_pSysData->m_pContainer->crt()->strlen( lpszStr );
        int sub_len = g_pSysData->m_pContainer->crt()->strlen( lpszSub );

        const char * lpszStrSub = lpszStr + str_len - sub_len;

        if( ( 0 == ret ) && ( str_len < sub_len ) )
        {
            ret = 1;
        }

        for( int i = 0; ( 0 == ret ) && ( i < sub_len ); ++i )
        {
            if( lpszStrSub[i] != lpszSub[i] )
            {
                ret = 1;
                break;
            }
        }

        return ret;
    }

    int misc::trim( char * lpszStr, const char * lpszTrims )
    {
        int ret = 0;

        if( !lpszStr || !lpszTrims || ( 0 == lpszStr[0] ) || ( 0 == lpszTrims[0] ) )
        {
            return 1;
        }

        int nLen = g_pSysData->m_pContainer->crt()->strlen( lpszStr );

        char * lpszRight = lpszStr + nLen - 1;
        char * lpszLeft = lpszStr;

        while( *lpszLeft )
        {
            const char * lpszTrim = lpszTrims;
            while( *lpszTrim && ( *lpszTrim != *lpszLeft ) )
            {
                lpszTrim++;
            }
            if( *lpszTrim )
            {
                *lpszLeft++ = 0;
            }
            else
            {
                break;
            }
        }

        while( *lpszRight )
        {
            const char * lpszTrim = lpszTrims;
            while( *lpszTrim && ( *lpszTrim != *lpszRight ) )
            {
                lpszTrim++;
            }
            if( *lpszTrim )
            {
                *lpszRight-- = 0;
            }
            else
            {
                break;
            }
        }

        nLen = ( int )( lpszRight - lpszLeft + 1 );

        if( nLen > 0 )
        {
            if( lpszStr != lpszLeft )
            {
                g_pSysData->m_pContainer->crt()->memmove( lpszStr, lpszLeft, nLen );
                lpszStr[nLen] = 0;
            }
        }
        else
        {
            lpszStr[0] = 0;
        }

        return ret;
    }

    int misc::valid( const char * lpszStr, int nLen )
    {
        int ret = 0;
        int len = g_pSysData->m_pContainer->crt()->strlen( lpszStr );
        if( len + 1 > nLen )
        {
            ret = 1;
        }
        return ret;
    }

    // 
    // 拷贝文件
    // 
    int misc::copy( const char * lpszSrcFile, const char * lpszDstFile )
    {
        int ret = 0;

        xos::i_file * pSrc = 0, * pDst = 0;
        char buf[4096];
        int nLen = 0;

        if( 0 == ret )
        {
            pSrc = g_pSysData->m_pContainer->file();
            pDst = g_pSysData->m_pContainer->file();
            if( !pSrc || !pDst )
            {
                ret = 1;
            }
        }
        if( 0 == ret )
        {
            ret = pSrc->open( lpszSrcFile, xos::i_file::enumFileAccessFlag::FILE_READ, xos::i_file::enumFileShareFlag::SHARE_READ, xos::i_file::enumFileOpenFlag::FILE_OPEN );
        }
        if( 0 == ret )
        {
            ret = pDst->open( lpszDstFile, xos::i_file::enumFileAccessFlag::FILE_WRITE, xos::i_file::enumFileShareFlag::SHARE_READ, xos::i_file::enumFileOpenFlag::FILE_CREATE );
        }
        while( 0 == ret )
        {
            nLen = pSrc->read( buf, sizeof( buf ) );
            if( nLen > 0 )
            {
                pDst->write( buf, nLen );
            }
            else
            {
                break;
            }
        }

        xos_stl::release_interface( pDst );
        xos_stl::release_interface( pSrc );

        return ret;
    }

    // 
    // 常用判断方法
    // 
    bool misc::is_valid_email_addr( const char * lpszEmail )
    {
        using namespace xos_stl;

        CRegexpT< char > regexp( "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$" );
        bool bRet = false;

        MatchResult result = regexp.Match( lpszEmail );
        if( result.IsMatched() )
        {
            bRet = true;
        }

        return bRet;
    }

    bool misc::is_valid_id_card( const char * lpszIdCard )
    {
        bool bRet = false;
        id_card obj;
        bRet = obj.is_valid_id_card( lpszIdCard );
        return bRet;
    }

    bool misc::is_valid_phone( const char * lpszPhone )
    {
        bool bRet = true;
        int nPhoneLen = 0;
        if( bRet && !lpszPhone )
        {
            bRet = false;
        }
        if( bRet )
        {
            nPhoneLen = g_pSysData->m_pContainer->crt()->strlen( lpszPhone );
            if( 11 != nPhoneLen )
            {
                bRet = false;
            }
        }
        for( int i = 0; bRet && ( i < nPhoneLen ); ++i )
        {
            if( !isdigit( lpszPhone[i] ) )
            {
                bRet = false;
                break;
            }
        }
        return bRet;
    }

    // 
    // float double比较
    // 
    int misc::double_compare( double d1, double d2 )
    {
        int ret = 0;

        double v = d1 - d2;
        double f = abs( v );

        if( f > DBL_MIN )
        {
            if( v < 0 )
            {
                ret = -1;
            }
            else
            {
                ret = 1;
            }
        }

        return ret;
    }

    int misc::float_compare( float f1, float f2 )
    {
        int ret = 0;

        float v = f1 - f2;
        float f = abs( v );

        if( f > FLT_MIN )
        {
            if( v < 0 )
            {
                ret = -1;
            }
            else
            {
                ret = 1;
            }
        }

        return ret;
    }

} // xos_common
